package org.jing.core.thread;

import org.jing.core.lang.data.Carrier;
import org.jing.core.logger.JingLogger;
import org.jing.core.thread.itf.BaseMultiplyThread;
import org.jing.core.util.ClassUtil;
import org.jing.core.util.GenericUtil;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.LinkedList;

/**
 * Description: <br>
 *
 * @author bks <br>
 * @since 2020-05-26 <br>
 */
@SuppressWarnings({ "unused", "WeakerAccess" })
public class ThreadFactory {
    private static final JingLogger LOGGER = JingLogger.getLogger(ThreadFactory.class);

    private static int limitCount = 16;

    private static final HashSet<ThreadDispatcher> RUNNING_SET = new HashSet<>();

    private static final LinkedList<ThreadDispatcher> WAITING_LIST = new LinkedList<>();

    public static synchronized void create(Class<? extends BaseMultiplyThread> type) {
        create(type, true);
    }

    public static synchronized void create(Class<? extends BaseMultiplyThread> type, boolean wait) {
        create(type, null, wait);
    }

    public static synchronized void create(Class<? extends BaseMultiplyThread> type, Carrier configC, boolean wait) {
        BaseMultiplyThread thread = ClassUtil.createInstance(type);
        create(thread, configC, wait);
    }

    public static synchronized void create(BaseMultiplyThread thread) {
        create(thread, null, true);
    }

    public static synchronized void create(BaseMultiplyThread thread, Carrier configC, boolean wait) {
        LOGGER.debug("create thread: {}, wait: {}", thread.getClass(), wait);
        if (null != configC) {
            Class type = ClassUtil.findSuperClass(thread.getClass(), BaseMultiplyThread.class);
            if (null != type) {
                Type[] types = ((ParameterizedType) type.getGenericSuperclass()).getActualTypeArguments();
                if (GenericUtil.count(types) != 0) {
                    Class configType = (Class) types[0];
                    thread.setConfig(configC.serialize(configType));
                }
            }
        }
        ThreadDispatcher dispatcher = new ThreadDispatcher(thread, wait);
        WAITING_LIST.addLast(dispatcher);
        update();
    }

    static synchronized void remove(ThreadDispatcher dispatcher) {
        RUNNING_SET.remove(dispatcher);
        update();
    }

    public static synchronized void setLimitCount(int limitCount) {
        ThreadFactory.limitCount = limitCount;
        update();
    }

    private static synchronized void update() {
        if (!WAITING_LIST.isEmpty()) {
            ThreadDispatcher dispatcher = WAITING_LIST.removeLast();
            if (!dispatcher.canWait()) {
                RUNNING_SET.add(dispatcher);
                dispatcher.start();
            }
            else {
                WAITING_LIST.addLast(dispatcher);
            }
        }
        if (RUNNING_SET.size() < limitCount && !WAITING_LIST.isEmpty()) {
            ThreadDispatcher dispatcher = WAITING_LIST.removeFirst();
            RUNNING_SET.add(dispatcher);
            dispatcher.start();
        }
    }
}
